package com.codeoss.module.account.service.impl;

import java.math.BigDecimal;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.codeoss.framework.service.impl.BaseService;
import com.codeoss.framework.util.DateUtil;
import com.codeoss.module.account.dao.AccountInvoiceMapper;
import com.codeoss.module.account.model.AccountInvoice;
import com.codeoss.module.account.model.AccountInvoiceLine;
import com.codeoss.module.account.model.AccountTax;
import com.codeoss.module.account.service.IAccountInvoiceLineService;
import com.codeoss.module.account.service.IAccountInvoiceService;
import com.codeoss.module.account.service.IAccountTaxService;
import com.codeoss.module.ir.service.IIrDocTypeService;
import com.codeoss.module.ir.service.IIrSequenceService;
import com.codeoss.module.purchase.model.PurchaseOrder;
import com.codeoss.module.purchase.model.PurchaseOrderLine;
import com.codeoss.module.purchase.service.IPurchaseOrderLineService;
import com.codeoss.module.purchase.service.IPurchaseOrderService;
import com.codeoss.module.sale.model.SaleOrder;
import com.codeoss.module.sale.model.SaleOrderLine;
import com.codeoss.module.sale.service.ISaleOrderLineService;
import com.codeoss.module.sale.service.ISaleOrderService;
import com.codeoss.module.stock.model.StockIn;
import com.codeoss.module.stock.model.StockInLine;
import com.codeoss.module.stock.model.StockOut;
import com.codeoss.module.stock.model.StockOutLine;
import com.codeoss.module.stock.service.IStockInLineService;
import com.codeoss.module.stock.service.IStockInService;
import com.codeoss.module.stock.service.IStockOutLineService;
import com.codeoss.module.stock.service.IStockOutService;

@Service
public class AccountInvoiceService extends BaseService<AccountInvoiceMapper, AccountInvoice>
		implements IAccountInvoiceService {
	
	@Autowired
	private IAccountInvoiceLineService accountInvoiceLineService;
	@Autowired
	private IAccountTaxService accountTaxService;
	
	@Autowired
	private ISaleOrderLineService saleOrderLineService;
	@Autowired
	private ISaleOrderService saleOrderService;
	@Autowired
	private IStockOutService stockOutService;
	@Autowired
	private IStockOutLineService stockOutLineService;
	@Autowired
	private IPurchaseOrderService purchaseOrderService;
	@Autowired
	private IPurchaseOrderLineService purchaseOrderLineService;
	@Autowired
	private IStockInService stockInService;
	@Autowired
	private IStockInLineService stockInLineService;
	@Autowired
	private IIrDocTypeService irDocTypeService;
	@Autowired
	private DateUtil dateUtil;
	@Autowired
	private IIrSequenceService irSequenceService;

	@Override
	public BigDecimal calculateAmountTotal(Long id) {
		// TODO Auto-generated method stub
		QueryWrapper<AccountInvoiceLine> lineQuery = new QueryWrapper<AccountInvoiceLine>();
		lineQuery.eq("account_invoice_id", id);
		List<AccountInvoiceLine> lineList = accountInvoiceLineService.list(lineQuery);
		BigDecimal amountTotal = new BigDecimal(0);
		for (AccountInvoiceLine line : lineList) {
			BigDecimal subTotal = line.getAmountSubtotal();
			if (subTotal != null) {
				amountTotal = amountTotal.add(subTotal);
			}
		}
		return amountTotal;
	}

	@Override
	public BigDecimal calculateAmountUntaxed(Long id) {
		// TODO Auto-generated method stub
		QueryWrapper<AccountInvoiceLine> lineQuery = new QueryWrapper<AccountInvoiceLine>();
		lineQuery.eq("account_invoice_id", id);
		List<AccountInvoiceLine> lineList = accountInvoiceLineService.list(lineQuery);
		BigDecimal amountUntaxed = new BigDecimal(0);
		for (AccountInvoiceLine line : lineList) {
			BigDecimal qtyOrdered = line.getQtyInvoiced();
			BigDecimal total = qtyOrdered.multiply(line.getPriceEntered());
			amountUntaxed = amountUntaxed.add(total);
		}
		return amountUntaxed;
	}

	@Override
	public BigDecimal calculateAmountTax(Long id) {
		// TODO Auto-generated method stub
		QueryWrapper<AccountInvoiceLine> lineQuery = new QueryWrapper<AccountInvoiceLine>();
		lineQuery.eq("account_invoice_id", id);
		List<AccountInvoiceLine> lineList = accountInvoiceLineService.list(lineQuery);
		BigDecimal amountTax = new BigDecimal(0);
		for (AccountInvoiceLine line : lineList) {
			Long taxId = line.getAccountTaxId();
			BigDecimal qtyOrdered = line.getQtyInvoiced();
			BigDecimal total = qtyOrdered.multiply(line.getPriceEntered());
			AccountTax accountTax = accountTaxService.getById(taxId);
			BigDecimal accountRate = accountTax.getRate().divide(new BigDecimal(100));
			amountTax = amountTax.add(total.multiply(accountRate));
		}
		return amountTax;
	}

	@Override
	@Transactional
	public AccountInvoice generateInvoiceFromSaleOrder(Long saleOrderId) {
		// TODO Auto-generated method stub
		AccountInvoice accountInvoice=new AccountInvoice();
		SaleOrder saleOrder=saleOrderService.getById(saleOrderId);
		String docStatus=saleOrder.getDocStatus();
		if(!"CO".equals(docStatus)) {
			throw new RuntimeException("请先完成单据");
		}
		accountInvoice.setSaleOrderId(saleOrderId);
		accountInvoice.setDocStatus("DR");
		Long docTypeId=irDocTypeService.getIrDocTypeIdByCode("saleinvoice");
		accountInvoice.setIrDocTypeId(docTypeId);
		accountInvoice.setSoTrx(true);
		accountInvoice.setDateInvoiced(dateUtil.getSqlNowDatetime());
		accountInvoice.setResPartnerId(saleOrder.getResPartnerId());
		accountInvoice.setProductPricelistId(saleOrder.getProductPricelistId());
		accountInvoice.setDocumentNo(irSequenceService.getNextSequenceNo("saleinvoice"));
		insert(accountInvoice);
		
		List<SaleOrderLine> saleOrderLineList=saleOrderLineService.getLineListBySaleOrderId(saleOrderId);
		int lineNo=10;
		for(SaleOrderLine saleOrderLine:saleOrderLineList) {
			AccountInvoiceLine accountInvoiceLine=new AccountInvoiceLine();
			accountInvoiceLine.setLine(lineNo);
			accountInvoiceLine.setProductProductId(saleOrderLine.getProductProductId());
			accountInvoiceLine.setProductAttrSetInstanceId(saleOrderLine.getProductAttrSetInstanceId());
			accountInvoiceLine.setQtyEntered(saleOrderLine.getQtyEntered());
			accountInvoiceLine.setUomUomId(saleOrderLine.getUomUomId());
			accountInvoiceLine.setPriceEntered(saleOrderLine.getPriceEntered());
			accountInvoiceLine.setAccountTaxId(saleOrderLine.getAccountTaxId());
			accountInvoiceLine.setAccountInvoiceId(accountInvoice.getId());
			accountInvoiceLine.setSaleOrderLineId(saleOrderLine.getId());
			lineNo+=10;
			accountInvoiceLineService.insert(accountInvoiceLine);
		}
		accountInvoice.setAmountUntaxed(calculateAmountUntaxed(accountInvoice.getId()));
		accountInvoice.setAmountTax(calculateAmountTax(accountInvoice.getId()));
		accountInvoice.setAmountTotal(calculateAmountTotal(accountInvoice.getId()));
		update(accountInvoice);
		return accountInvoice;
	}

	@Override
	@Transactional
	public AccountInvoice generateInvoiceFromPurchaseOrder(Long purchaseOrderId) {
		// TODO Auto-generated method stub
		AccountInvoice accountInvoice=new AccountInvoice();
		PurchaseOrder purchaseOrder=purchaseOrderService.getById(purchaseOrderId);
		String docStatus=purchaseOrder.getDocStatus();
		if(!"CO".equals(docStatus)) {
			throw new RuntimeException("请先完成单据");
		}
		accountInvoice.setPurchaseOrderId(purchaseOrderId);
		accountInvoice.setDocStatus("DR");
		Long docTypeId=irDocTypeService.getIrDocTypeIdByCode("purchaseinvoice");
		accountInvoice.setIrDocTypeId(docTypeId);
		accountInvoice.setSoTrx(false);
		accountInvoice.setDateInvoiced(dateUtil.getSqlNowDatetime());
		accountInvoice.setResPartnerId(purchaseOrder.getResPartnerId());
		accountInvoice.setProductPricelistId(purchaseOrder.getProductPricelistId());
		accountInvoice.setDocumentNo(irSequenceService.getNextSequenceNo("purchaseinvoice"));
		insert(accountInvoice);
		
		List<PurchaseOrderLine> purchaseOrderLineList=purchaseOrderLineService.getLineListByPurchaseOrderId(purchaseOrderId);
		int lineNo=10;
		for(PurchaseOrderLine purchaseOrderLine:purchaseOrderLineList) {
			AccountInvoiceLine accountInvoiceLine=new AccountInvoiceLine();
			accountInvoiceLine.setLine(lineNo);
			accountInvoiceLine.setProductProductId(purchaseOrderLine.getProductProductId());
			accountInvoiceLine.setProductAttrSetInstanceId(purchaseOrderLine.getProductAttrSetInstanceId());
			accountInvoiceLine.setQtyEntered(purchaseOrderLine.getQtyEntered());
			accountInvoiceLine.setUomUomId(purchaseOrderLine.getUomUomId());
			accountInvoiceLine.setPriceEntered(purchaseOrderLine.getPriceEntered());
			accountInvoiceLine.setAccountTaxId(purchaseOrderLine.getAccountTaxId());
			accountInvoiceLine.setAccountInvoiceId(accountInvoice.getId());
			accountInvoiceLine.setPurchaseOrderLineId(purchaseOrderLine.getId());
			lineNo+=10;
			accountInvoiceLineService.insert(accountInvoiceLine);
		}
		accountInvoice.setAmountUntaxed(calculateAmountUntaxed(accountInvoice.getId()));
		accountInvoice.setAmountTax(calculateAmountTax(accountInvoice.getId()));
		accountInvoice.setAmountTotal(calculateAmountTotal(accountInvoice.getId()));
		update(accountInvoice);
		return accountInvoice;
	}

	@Override
	@Transactional
	public AccountInvoice generateInvoiceFromStockOut(Long stockOutId) {
		// TODO Auto-generated method stub
		AccountInvoice accountInvoice=new AccountInvoice();
		StockOut stockOut=stockOutService.getById(stockOutId);
		String docStatus=stockOut.getDocStatus();
		if(!"CO".equals(docStatus)) {
			throw new RuntimeException("请先完成单据");
		}
		accountInvoice.setStockOutId(stockOutId);
		accountInvoice.setDocStatus("DR");
		Long docTypeId=irDocTypeService.getIrDocTypeIdByCode("saleinvoice");
		accountInvoice.setIrDocTypeId(docTypeId);
		accountInvoice.setSoTrx(true);
		accountInvoice.setDateInvoiced(dateUtil.getSqlNowDatetime());
		accountInvoice.setResPartnerId(stockOut.getResPartnerId());
		accountInvoice.setDocumentNo(irSequenceService.getNextSequenceNo("saleinvoice"));
		Long saleOrderId=stockOut.getSaleOrderId();
		if(saleOrderId!=null) {
			SaleOrder saleOrder=saleOrderService.getById(saleOrderId);
			accountInvoice.setProductPricelistId(saleOrder.getProductPricelistId());
			accountInvoice.setSaleOrderId(saleOrder.getId());
		}
		insert(accountInvoice);
		
		List<StockOutLine> stockOutLineList=stockOutLineService.getLineListByStockOutId(stockOutId);
		int lineNo=10;
		for(StockOutLine stockOutLine:stockOutLineList) {
			AccountInvoiceLine accountInvoiceLine=new AccountInvoiceLine();
			accountInvoiceLine.setLine(lineNo);
			accountInvoiceLine.setProductProductId(stockOutLine.getProductProductId());
			accountInvoiceLine.setProductAttrSetInstanceId(stockOutLine.getProductAttrSetInstanceId());
			accountInvoiceLine.setQtyEntered(stockOutLine.getQtyEntered());
			accountInvoiceLine.setUomUomId(stockOutLine.getUomUomId());
			
			Long saleOrderLineId=stockOutLine.getSaleOrderLineId();
			if(saleOrderLineId!=null) {
				SaleOrderLine saleOrderLine=saleOrderLineService.getById(saleOrderLineId);
				accountInvoiceLine.setPriceEntered(saleOrderLine.getPriceEntered());
				accountInvoiceLine.setAccountTaxId(saleOrderLine.getAccountTaxId());
				accountInvoiceLine.setSaleOrderLineId(saleOrderLine.getId());
			}
			accountInvoiceLine.setStockOutLineId(stockOutLine.getId());	
			accountInvoiceLine.setAccountInvoiceId(accountInvoice.getId());
			
			lineNo+=10;
			accountInvoiceLineService.insert(accountInvoiceLine);
		}
		accountInvoice.setAmountUntaxed(calculateAmountUntaxed(accountInvoice.getId()));
		accountInvoice.setAmountTax(calculateAmountTax(accountInvoice.getId()));
		accountInvoice.setAmountTotal(calculateAmountTotal(accountInvoice.getId()));
		update(accountInvoice);
		return accountInvoice;
	}

	@Override
	@Transactional
	public AccountInvoice generateInvoiceFromStockIn(Long stockInId) {
		// TODO Auto-generated method stub
		AccountInvoice accountInvoice=new AccountInvoice();
		StockIn stockIn=stockInService.getById(stockInId);
		String docStatus=stockIn.getDocStatus();
		if(!"CO".equals(docStatus)) {
			throw new RuntimeException("请先完成单据");
		}
		accountInvoice.setStockInId(stockInId);
		accountInvoice.setDocStatus("DR");
		Long docTypeId=irDocTypeService.getIrDocTypeIdByCode("purchaseinvoice");
		accountInvoice.setIrDocTypeId(docTypeId);
		accountInvoice.setSoTrx(false);
		accountInvoice.setDateInvoiced(dateUtil.getSqlNowDatetime());
		accountInvoice.setResPartnerId(stockIn.getResPartnerId());
		accountInvoice.setDocumentNo(irSequenceService.getNextSequenceNo("purchaseinvoice"));
		Long purchaseOrderId=stockIn.getPurchaseOrderId();
		if(purchaseOrderId!=null) {
			PurchaseOrder purchaseOrder=purchaseOrderService.getById(purchaseOrderId);
			accountInvoice.setProductPricelistId(purchaseOrder.getProductPricelistId());
			accountInvoice.setPurchaseOrderId(purchaseOrderId);
		}
		insert(accountInvoice);
		
		List<StockInLine> stockInLineList=stockInLineService.getLineListByStockInId(stockInId);
		int lineNo=10;
		for(StockInLine stockInLine:stockInLineList) {
			AccountInvoiceLine accountInvoiceLine=new AccountInvoiceLine();
			accountInvoiceLine.setLine(lineNo);
			accountInvoiceLine.setProductProductId(stockInLine.getProductProductId());
			accountInvoiceLine.setProductAttrSetInstanceId(stockInLine.getProductAttrSetInstanceId());
			accountInvoiceLine.setQtyEntered(stockInLine.getQtyEntered());
			accountInvoiceLine.setUomUomId(stockInLine.getUomUomId());
			
			Long purchaseOrderLineId=stockInLine.getPurchaseOrderLineId();
			if(purchaseOrderLineId!=null) {
				PurchaseOrderLine purchaseOrderLine=purchaseOrderLineService.getById(purchaseOrderLineId);
				accountInvoiceLine.setPriceEntered(purchaseOrderLine.getPriceEntered());
				accountInvoiceLine.setAccountTaxId(purchaseOrderLine.getAccountTaxId());
				accountInvoiceLine.setPurchaseOrderLineId(purchaseOrderLine.getId());
			}
			accountInvoiceLine.setStockInLineId(stockInLine.getId());	
			accountInvoiceLine.setAccountInvoiceId(accountInvoice.getId());
			
			lineNo+=10;
			accountInvoiceLineService.insert(accountInvoiceLine);
		}
		accountInvoice.setAmountUntaxed(calculateAmountUntaxed(accountInvoice.getId()));
		accountInvoice.setAmountTax(calculateAmountTax(accountInvoice.getId()));
		accountInvoice.setAmountTotal(calculateAmountTotal(accountInvoice.getId()));
		update(accountInvoice);
		return accountInvoice;
	}

	@Override
	@Transactional
	public void prepareIt(Long id) {
		// TODO Auto-generated method stub
		List<AccountInvoiceLine> accountInvoiceLineList=accountInvoiceLineService.getLineListByAccountInvoiceId(id);
		if(accountInvoiceLineList==null ||accountInvoiceLineList.size()==0 ) {
			throw new RuntimeException("没有行明细");
		}
	}

	@Override
	@Transactional
	public void approveIt(Long id) {
		// TODO Auto-generated method stub
		AccountInvoice accountInvoice=getById(id);
		accountInvoice.setApproved(true);
		update(accountInvoice);
	}

	@Override
	@Transactional
	public void rejectIt(Long id) {
		// TODO Auto-generated method stub
		AccountInvoice accountInvoice=getById(id);
		accountInvoice.setApproved(false);
		update(accountInvoice);
	}

	@Override
	@Transactional
	public void completeIt(Long id) {
		// TODO Auto-generated method stub
		AccountInvoice accountInvoice=getById(id);
		accountInvoice.setDocStatus("CO");
		update(accountInvoice);
		if(!accountInvoice.getApproved()) {
			return;
		}
		List<AccountInvoiceLine> accountInvoiceLineList=accountInvoiceLineService.getLineListByAccountInvoiceId(id);
		for(int i=0;i<accountInvoiceLineList.size();i++) {
			AccountInvoiceLine accountInvoiceLine=accountInvoiceLineList.get(i);
			Long saleOrderLineId=accountInvoiceLine.getSaleOrderLineId();
			if(saleOrderLineId!=null) {
				SaleOrderLine saleOrderLine=saleOrderLineService.getById(saleOrderLineId);
				BigDecimal qtyInvoiced=saleOrderLine.getQtyInvoiced();
				if(qtyInvoiced==null) {
					qtyInvoiced=new BigDecimal(0);
				}
				qtyInvoiced=qtyInvoiced.add(accountInvoiceLine.getQtyEntered());
				saleOrderLine.setQtyInvoiced(qtyInvoiced);
				saleOrderLineService.update(saleOrderLine);
			}
			Long purchaseOrderLineId=accountInvoiceLine.getPurchaseOrderLineId();
			if(purchaseOrderLineId!=null) {
				PurchaseOrderLine purchaseOrderLine=purchaseOrderLineService.getById(purchaseOrderLineId);
				BigDecimal qtyInvoiced=purchaseOrderLine.getQtyInvoiced();
				if(qtyInvoiced==null) {
					qtyInvoiced=new BigDecimal(0);
				}
				qtyInvoiced=qtyInvoiced.add(accountInvoiceLine.getQtyEntered());
				purchaseOrderLine.setQtyInvoiced(qtyInvoiced);
				purchaseOrderLineService.update(purchaseOrderLine);
			}
		}
	}

	@Override
	@Transactional
	public void setDocStatus(Long id, String docStatus) {
		// TODO Auto-generated method stub
		AccountInvoice accountInvoice=getById(id);
		accountInvoice.setDocStatus(docStatus);
		update(accountInvoice);
	}
}